package com.sdy.hospitalguard.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdy.common.model.BizException;
import com.sdy.common.utils.Assert;
import com.sdy.hospitalguard.biz.dto.EscortAssociatedUserDTO;
import com.sdy.hospitalguard.biz.dto.EscortManageDTO;
import com.sdy.hospitalguard.biz.dto.MatchingPeopleDTO;
import com.sdy.hospitalguard.biz.mapper.EscortAssociatedMapper;
import com.sdy.hospitalguard.biz.model.*;
import com.sdy.hospitalguard.biz.service.*;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 陪护关联表 服务实现类
 * </p>
 *
 * @author zzq
 * @since 2020-05-08
 */
@Slf4j
@Service
public class EscortAssociatedServiceImpl extends BaseServiceImpl<EscortAssociated> implements EscortAssociatedService {

    @Autowired
    private EscortAssociatedMapper escortAssociatedMapper;
    @Autowired
    private HospitalUserService hospitalUserService;
    @Autowired
    private PatientInformationService patientInformationService;
    @Autowired
    private RegulationsService regulationsService;
    @Autowired
    private VisitAppointmentService visitAppointmentService;
    @Autowired
    private MatchingPeopleService matchingPeopleService;
    @Autowired
    private NoticeService noticeService;

    @Override
    public void saveEscortAssociated(EscortAssociatedUserDTO escortAssociatedUserDTO) throws BizException {
        EscortAssociated escortAssociated = new EscortAssociated();
        escortAssociated.setPatientId(escortAssociatedUserDTO.getPatientId());
        escortAssociated.setUserId(escortAssociatedUserDTO.getUserId());
        // 判断人员当前是否是患者，是则无法注册成陪护
        LambdaQueryWrapper<PatientInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PatientInformation::getUserId, escortAssociated.getUserId());
        queryWrapper.eq(PatientInformation::getPatientState, 0);
        Assert.notNull(patientInformationService.getOne(queryWrapper), "您当前是患者无法成为陪护人员!");
        // 判断人员当前是否存在有效的绑定患者记录，是则无法重复绑定
        LambdaQueryWrapper<EscortAssociated> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EscortAssociated::getPatientId, escortAssociated.getPatientId());
        wrapper.eq(EscortAssociated::getUserId, escortAssociated.getUserId());
        wrapper.ne(EscortAssociated::getAttendantState, 1);
        wrapper.ne(EscortAssociated::getFlowState, 2);
        wrapper.ne(EscortAssociated::getFlowState, 3);
        Assert.notNull(getOne(wrapper), "不能重复关联同个患者!");
        // 新增陪护信息记录
        // 判断此陪护人员是否有正在陪护的患者，是新增的患者对其状态直接变为待陪护（到时候要切换成正在陪护的时候再发起申请），否直接申请
        if (getOne(escortAssociated.getUserId()) == null) {
            save(escortAssociated.setCreateTime(new Date()).setAttendantState(2).setFlowState(4));
            // 发送预约申请,目前无法到护士站
            Integer id = escortAssociated.getUserId();
            String name = hospitalUserService.getById(id).getName();
            Integer handlerId = patientInformationService.getById(escortAssociated.getPatientId()).getUserId();
            Notice notice = new Notice();
            notice.setAssociationId(escortAssociated.getId());
            notice.setSendUserId(id);
            notice.setHandlerId(handlerId);
            notice.setMessageContent(name + "向" + hospitalUserService.getById(handlerId).getName() + "发起陪护关联");
            notice.setType(1);
            notice.setState(1);
            notice.setResult(0);
            notice.setCreateTime(new Date());
            noticeService.save(notice);
        } else {
            save(escortAssociated.setCreateTime(new Date()).setAttendantState(2).setFlowState(1));
        }
        // 修改陪护人员个人信息
        hospitalUserService.update(new LambdaUpdateWrapper<HospitalUser>()
                .eq(HospitalUser::getId, escortAssociatedUserDTO.getUserId())
                .set(HospitalUser::getName, escortAssociatedUserDTO.getName())
                .set(HospitalUser::getIdCard, escortAssociatedUserDTO.getIdCard())
                .set(HospitalUser::getPhone, escortAssociatedUserDTO.getPhone()));
    }

    @Override
    public EscortAssociated getOne(Integer userId) {
        LambdaQueryWrapper<EscortAssociated> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(EscortAssociated::getUserId, userId);
        lambdaQueryWrapper.eq(EscortAssociated::getAttendantState, 0);
        lambdaQueryWrapper.eq(EscortAssociated::getFlowState, 0);
        lambdaQueryWrapper.ne(EscortAssociated::getStatus, 1);
        return getOne(lambdaQueryWrapper);
    }

    @Override
    public Integer cutoverPatient(Integer userId, Integer id) throws BizException {
        // 查询当前用户正在陪护的患者
        EscortAssociated escortAssociated = getOne(userId);
        Assert.notNull(escortAssociated, "您有正在陪护的患者，无法主动去切换成正在陪护其他的患者");
        // 修改陪护的原患者的陪护状态
        if (escortAssociated != null) {
            update(new LambdaUpdateWrapper<EscortAssociated>()
                    .eq(EscortAssociated::getId, escortAssociated.getId())
                    .set(EscortAssociated::getFlowState, 1)
                    .set(EscortAssociated::getUpdateTime, new Date()));
        }
        // 判断即将切换成的患者的陪护状态
        Integer flowState = getById(id).getFlowState();
        Assert.notTrue((flowState == 1), "只有待陪护的患者才能切换陪护状态!");
        // 判断此人对预选患者是否曾今发过申请，否则发起陪护申请走审核，是则直接切换，判断规则
        if (getById(id).getAttendantState() == 2) {
            // 发送预约申请,目前无法到护士站
            String name = hospitalUserService.getById(userId).getName();
            Integer handlerId = patientInformationService.getById(getById(id).getPatientId()).getUserId();
            // 查询是否有提交的申请记录
            QueryWrapper<Notice> wrapper = new QueryWrapper<>();
            wrapper.eq("association_id", getById(id).getId());
            wrapper.eq("send_user_id", userId);
            wrapper.eq("handler_id", handlerId);
            wrapper.eq("type", 1);
            wrapper.ne("result", 1);
            Assert.isTrue(noticeService.list(wrapper).size() > 0, "你已向该用户发起了申请，请等待处理或联系他");
            Notice notice = new Notice();
            notice.setAssociationId(getById(id).getId());
            notice.setSendUserId(userId);
            notice.setHandlerId(handlerId);
            notice.setMessageContent(name + "向" + hospitalUserService.getById(handlerId).getName() + "发起陪护关联");
            notice.setType(1);
            notice.setState(1);
            notice.setResult(0);
            notice.setCreateTime(new Date());
            noticeService.save(notice);
            return 1;
        } else {
            // 规则池判断
            Integer limitedSize = Integer.parseInt(regulationsService.selectEscortAssociatedRule(getById(id).getPatientId()));
            QueryWrapper<EscortAssociated> wrapper = new QueryWrapper<>();
            wrapper.eq("patient_id", getById(id).getPatientId());
            wrapper.eq("flow_state", 0);
            wrapper.ne("status", 1);
            Assert.isTrue((list(wrapper).size() >= limitedSize), "此患者已超出陪护人数上限，无法切换!");
            // 修改即将陪护的患者的陪护状态
            update(new LambdaUpdateWrapper<EscortAssociated>()
                    .eq(EscortAssociated::getId, id)
                    .set(EscortAssociated::getFlowState, 0)
                    .set(EscortAssociated::getUpdateTime, new Date()));
            // 判断更新好的正在陪护的患者，与原来的正在陪护的患者是否同个楼，是则不用更新陪护人的门禁信息，否则删除和新增
            if (escortAssociated == null) {
                HospitalUser hospitalUser = hospitalUserService.getById(userId);
                MatchingPeople matchingPeople = new MatchingPeople();
                matchingPeople.setUserId(userId);
                matchingPeople.setName(hospitalUser.getName());
                matchingPeople.setCardId(hospitalUser.getIdCard());
                matchingPeople.setRemark("陪护人员");
                matchingPeople.setFaceId(userId);
                matchingPeople.setPhotoPath(hospitalUser.getPhotoPath());
                matchingPeople.setBuilding(patientInformationService.getById(getById(id).getPatientId()).getFloorId().toString());
                matchingPeople.setLastChange(String.valueOf(System.currentTimeMillis()/1000));
                matchingPeople.setStatus(0);
                boolean success = matchingPeopleService.add(matchingPeople);
                Assert.notTrue(success, "切换失败!");
            } else {
                if (Integer.parseInt(patientInformationService.getById(escortAssociated.getPatientId()).getFloorId()) ==
                        Integer.parseInt(patientInformationService.getById(getById(id).getPatientId()).getFloorId())) {

                } else {
                    MatchingPeopleDTO matchingPeopleDTO = new MatchingPeopleDTO();
                    matchingPeopleDTO.setUserId(userId);
                    matchingPeopleDTO.setPatientId(escortAssociated.getPatientId());
                    matchingPeopleDTO.setBuilding(patientInformationService.getById(escortAssociated.getPatientId()).getFloorId().toString());
                    boolean success1 = matchingPeopleService.delete(matchingPeopleDTO);

                    HospitalUser hospitalUser = hospitalUserService.getById(userId);
                    MatchingPeople matchingPeople = new MatchingPeople();
                    matchingPeople.setUserId(userId);
                    matchingPeople.setName(hospitalUser.getName());
                    matchingPeople.setCardId(hospitalUser.getIdCard());
                    matchingPeople.setRemark("陪护人员");
                    matchingPeople.setFaceId(userId);
                    matchingPeople.setPhotoPath(hospitalUser.getPhotoPath());
                    matchingPeople.setBuilding(patientInformationService.getById(getById(id).getPatientId()).getFloorId().toString());
                    matchingPeople.setLastChange(String.valueOf(System.currentTimeMillis()/1000));
                    matchingPeople.setStatus(0);
                    boolean success2 = matchingPeopleService.add(matchingPeople);

                    Assert.notTrue((success1 && success2), "切换失败!");
                }
            }
            return 0;
        }
    }

    @Override
    public void cancelPatient(Integer userId, Integer id) throws BizException {
        // 判断即将解除绑定的患者的陪护状态
        Integer flowState = getById(id).getFlowState();
        Assert.notTrue((flowState == 0), "只有正在陪护的患者才能解除绑定!");
        update(new LambdaUpdateWrapper<EscortAssociated>()
                .eq(EscortAssociated::getId, id)
                .set(EscortAssociated::getFlowState, 1)
                .set(EscortAssociated::getUpdateTime, new Date()));
        // 若解绑的陪护人员为正在陪护状态则需将其从门禁设备信息里移除
        if (flowState == 0) {
            Integer patientId = getById(id).getPatientId();
            PatientInformation patientInformation = patientInformationService.getById(patientId);
            MatchingPeopleDTO matchingPeopleDTO = new MatchingPeopleDTO();
            matchingPeopleDTO.setUserId(userId);
            matchingPeopleDTO.setPatientId(patientId);
            matchingPeopleDTO.setBuilding(patientInformation.getFloorId().toString());
            boolean success = matchingPeopleService.delete(matchingPeopleDTO);
            Assert.notTrue(success, "解绑失败!");
        }
    }

    @Override
    public Integer confirmIdentity(Integer userId, Integer building) {
        // 是否是患者
        PatientInformation patientInformation = patientInformationService.getOne(Wrappers.<PatientInformation>lambdaQuery()
                .eq(PatientInformation::getUserId, userId)
                .eq(PatientInformation::getPatientState, 0)
                .eq(PatientInformation::getFloorId, building));
        // 是否是探视者
        List<VisitAppointment> list = visitAppointmentService.list(Wrappers.<VisitAppointment>lambdaQuery()
                .eq(VisitAppointment::getUserId, userId)
                .eq(VisitAppointment::getAppointmentState, 0)
                .in(VisitAppointment::getVisitState, 0, 1, 2));
                //.ne(VisitAppointment::getStatus, 1));
        // 是否是陪护
        List<EscortAssociated> escortAssociatedList = list(Wrappers.<EscortAssociated>lambdaQuery()
                .eq(EscortAssociated::getUserId, userId)
                .eq(EscortAssociated::getAttendantState, 0)
                .eq(EscortAssociated::getFlowState, 0));
                //.ne(EscortAssociated::getStatus, 1));
        if (patientInformation != null) {
            return 0;
        }
        if (list.size() > 0) {
            Integer sign = 0;
            for (int i=0; i<list.size(); i++) {
                if (Integer.parseInt(patientInformationService.getById(list.get(i).getPatientId()).getFloorId()) == building) {
                    sign = 1;
                    break;
                }
            }
            if (sign == 0) {
                return 1;
            } else {
                if (escortAssociatedList.size() > 0) {
                    Integer signI = 0;
                    for (int i=0; i<escortAssociatedList.size(); i++) {
                        if (Integer.parseInt(patientInformationService.getById(escortAssociatedList.get(i).getPatientId()).getFloorId()) == building) {
                            signI = 1;
                            break;
                        }
                    }
                    if (signI == 0) {
                        return 2;
                    } else {
                        return 3;
                    }
                } else {
                    return 2;
                }
            }
        } else if (escortAssociatedList.size() > 0) {
            return 1;
        } else {
            return 4;
        }
    }

    @Override
    public List<Integer> getVisitId(Integer userId, Integer building, Date date) {
        Integer type = confirmIdentity(userId, building);
        List<Integer> res = new ArrayList<>();
        if (type == 2 || type == 3) {
            QueryWrapper<VisitAppointment> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId);
            wrapper.eq("appointment_state", 0);
            wrapper.ne("visit_state", 3);
            wrapper.isNotNull("practical_start_time");
            wrapper.isNull("practical_end_time");
            wrapper.lt("visit_end_time", date);
            wrapper.orderByDesc("visit_end_time");
            List<VisitAppointment> visitAppointmentList = visitAppointmentService.list(wrapper);
            // 判断此人有没有探视超时记录
            if(visitAppointmentList.size() > 0) {
                for (int i=0; i<visitAppointmentList.size(); i++) {
                    if (Integer.parseInt(patientInformationService.getById(visitAppointmentList.get(i).getPatientId()).getFloorId()) == building) {
                        res.add(visitAppointmentList.get(i).getId());
                        break;
                    }
                }
                return res;
            }
            List<VisitAppointment> list = visitAppointmentService.list(Wrappers.<VisitAppointment>lambdaQuery()
                    .eq(VisitAppointment::getUserId, userId)
                    .eq(VisitAppointment::getAppointmentState, 0)
                    .in(VisitAppointment::getVisitState, 0, 1, 2)
                    .le(VisitAppointment::getVisitStartTime, date)
                    .ge(VisitAppointment::getVisitEndTime, date));
                    //.ne(VisitAppointment::getStatus, 1));
            if (list.size() > 0) {
                for (int i=0; i<list.size(); i++) {
                    if (Integer.parseInt(patientInformationService.getById(list.get(i).getPatientId()).getFloorId()) == building) {
                        res.add(list.get(i).getId());
                    }
                }
                if(res == null) {
                    res.add(-1);
                }
            } else {
                res.add(-1);
            }
            return res;
        }else {
            if (type == 4) {
                res.add(-3);
            } else {
                res.add(-type);
            }
            return res;
        }
    }

    @Override
    public IPage<EscortManageDTO> getEscortInformation(Page page, String message, Integer areaId, String start, String end, Integer userAreaId) {
        return escortAssociatedMapper.getEscortInformation(page, message, areaId, start, end, userAreaId);
    }

    @Override
    public List<EscortManageDTO> getEscortInformationList(String message, Integer areaId, String start, String end, Integer userAreaId) {
        return escortAssociatedMapper.getEscortInformation(message, areaId, start, end, userAreaId);
    }

    @Override
    public void saveEscort(Integer escortUserId, Integer patientId) throws BizException {
        // 判断人员当前是否是患者，是则无法注册成陪护
        LambdaQueryWrapper<PatientInformation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PatientInformation::getUserId, escortUserId);
        queryWrapper.eq(PatientInformation::getPatientState, 0);
        Assert.notNull(patientInformationService.getOne(queryWrapper), "您当前是患者无法成为陪护人员!");
        // 判断人员当前是否存在有效的绑定患者记录，是则无法重复绑定
        LambdaQueryWrapper<EscortAssociated> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EscortAssociated::getPatientId, patientId);
        wrapper.eq(EscortAssociated::getUserId, escortUserId);
        wrapper.ne(EscortAssociated::getAttendantState, 1);
        wrapper.ne(EscortAssociated::getFlowState, 2);
        wrapper.ne(EscortAssociated::getFlowState, 3);
        Assert.notNull(getOne(wrapper), "不能重复关联同个患者!");
        EscortAssociated escortAssociated = new EscortAssociated();
        escortAssociated.setPatientId(patientId);
        escortAssociated.setUserId(escortUserId);
        if (getOne(escortUserId) != null || getList(patientId).size() > 0) {
            save(escortAssociated.setCreateTime(new Date()).setAttendantState(2).setFlowState(1));
        } else {
            save(escortAssociated.setCreateTime(new Date()).setAttendantState(2).setFlowState(4));
            // 发送预约申请,目前无法到护士站
            String name = hospitalUserService.getById(escortUserId).getName();
            Integer sendUserId = patientInformationService.getById(patientId).getUserId();
            Notice notice = new Notice();
            notice.setAssociationId(escortAssociated.getId());
            notice.setSendUserId(sendUserId);
            notice.setHandlerId(escortUserId);
            notice.setMessageContent(hospitalUserService.getById(sendUserId).getName() + "向" + name + "发起陪护关联");
            notice.setType(1);
            notice.setState(1);
            notice.setResult(0);
            notice.setCreateTime(new Date());
            noticeService.save(notice);
        }
    }

    @Override
    public List<EscortAssociated> getList(Integer patientId) {
        LambdaQueryWrapper<EscortAssociated> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(EscortAssociated::getPatientId, patientId);
        lambdaQueryWrapper.eq(EscortAssociated::getAttendantState, 0);
        lambdaQueryWrapper.eq(EscortAssociated::getFlowState, 0);
        lambdaQueryWrapper.ne(EscortAssociated::getStatus, 1);
        return list(lambdaQueryWrapper);
    }

}
